package tcpclient

import (
	"errors"
	"fmt"
	"net"
	"util/log"
)

type recver interface {
	OnRecv(data []byte, size int)
}

type closer interface {
	OnClose()
}

type Tcpconn struct {
	conn      net.Conn
	connected bool
	handler   interface{}
	debug     bool
	debuginfo string
}

func (t *Tcpconn) Connected() bool {
	return t.connected
}

func (t *Tcpconn) Debug(val bool, info string) {
	t.debug = val
	t.debuginfo = info
}

func (t *Tcpconn) Connect(host string, port int) error {
	if t.connected {
		return errors.New("already connected")
	}

	addr := fmt.Sprintf("%s:%d", host, port)
	var err error
	t.conn, err = net.Dial("tcp", addr)

	if err != nil {
		return err
	}

	go t.read()
	t.connected = true
	return nil
}

func (t *Tcpconn) read() {
	data := make([]byte, 2048)
	for {
		n, err := t.conn.Read(data)
		if err != nil {

			log.TraceInfo("tcpclient", "socket close")
			t.connected = false
			if closer, ok := t.handler.(closer); ok {
				closer.OnClose()
			}
			return
		}

		if t.debug {
			log.LogDebug(t.debuginfo, "recv:", n, " bytes")
		}
		if recver, ok := t.handler.(recver); ok {
			recver.OnRecv(data, n)
		}
	}
}

func (t *Tcpconn) Send(buf []byte, size int) int {
	if t.connected {
		n, err := t.conn.Write(buf[:size])
		if err != nil {
			log.TraceInfo("tcpclient", err)
			return -1
		}
		if t.debug {
			log.LogDebug(t.debuginfo, "send:", n, " bytes")
		}
		return n
	}

	log.TraceInfo("tcpclient", "socket not connected")
	return -1
}

func (t *Tcpconn) Close() {
	if t.conn != nil {
		t.conn.Close()
		log.TraceInfo("tcpclient", "socket closed")
		if closer, ok := t.handler.(closer); ok {
			closer.OnClose()
		}
	}
}

func (t *Tcpconn) SetHandler(handler interface{}) {
	t.handler = handler
}

func CreateTcpclient() *Tcpconn {
	conn := &Tcpconn{}
	conn.connected = false
	return conn
}
